<template>
	<input
		ref="inputRef"
		v-model="currentValue"
		:placeholder="placeholderComputed"
		:disabled="disabled"
		:class="['wind-input-number', {
			'has-border' : border
		}]"
		type="tel"
		@input="onInput"
		@blur="onBlur"
		@focus="onFocus"
		@keydown.stop="onKeydown"
	>
</template>
<script lang="ts">
/**
 * InputNumber by shang 2022/9/20
 * @desc input-number 输入框-数字类型
 * @param {value}  [Number, String] - 输入框值
 * @param {integer}  [Boolean] - 是否int
 * @param {disabled}  [Boolean] - 是否禁用
 * @param {min}  [String, Number] - 最小值
 * @param {max}  [String, Number] - 最大值
 * @param {defaultValue}  [String, Number] - 默认值
 * @param {pointSize}  [String, Number] - 小数位
 * @param {intLength}  [String, Number] - 整数位
 * @param {placeholder}  [String] - 默认提示
 * @param {positive}  [Boolean] - 正数
 * @param {autoSelect}  [Boolean] - 自动选中
 *
 *
 * @event {change} 当绑定值变化时触发的事件	当前组件的值
 * @event {blur} 输入框失焦时触发
 * @event {focus} 输入框聚焦时触发
 */
import { defineComponent, computed, ref, watch } from 'vue'
import { getFxInstance } from '@/js/instance'
export default defineComponent({
	name: 'wind-input-number',
	props: {
		value: [Number, String],
		disabled: Boolean,
		readonly: Boolean,
		integer: Boolean,
		positive: Boolean,
		min: {
			type: Number,
			default: 0
		},
		max: {
			type: Number,
			default: Infinity
		},
		pointSize: {
			type: [String, Number],
			default: 4
		},
		intLength: {
			type: [String, Number],
			default: 8
		},
		placeholder: {
			type: String,
			default: '请输入'
		},
		border: Boolean,
		autoSelect: {
			type: Boolean,
			default: true
		}
	},
	emits: ['update:value', 'change', 'blur', 'focus', 'pressEnter', 'keydown'],
	setup (props, { emit, expose }) {
		const fxInstance = getFxInstance()
		const inputRef = ref<HTMLInputElement|null>(null)
		const currentValue = ref<number|string>(0)
		const intLength = typeof props.intLength === 'string' ? parseFloat(props.intLength) : props.intLength
		const computedNumberReg = computed(() => fxInstance.$fxUtils.regNumberIncludeNegative(props.pointSize))
		const format = (value:string|number|undefined):string|number => {
			value = String(value).replace(fxInstance.$fxUtils.regInputNumber(), '')
			return value === ''
				? 0 : props.integer
					? fxInstance.$fxUtils.floor(value) : props.pointSize
						? fxInstance.$fxUtils.toNumber(fxInstance.$fxUtils.toFixed(value, props.pointSize, false)) : fxInstance.$fxUtils.toNumber(value)
		}
		const formatString = (value:string|number) => {
			value = String(value).replace(fxInstance.$fxUtils.regInputNumber(), '')
			if (value.indexOf('.') !== -1) {
				const values = value.split('.')
				value = +(values[0]) + '.' + values[1]
			} else if (value.includes('-')) {
				value = '-' + value.replace(/-/g, '')
			} else {
				value = +value
			}
			const floorValue = Number(value)
			return value === '' ? '0' : props.integer ? Math.floor(floorValue) + '' : '' + value
		}
		const range = (value:string|number) => {
			return Math.max(Math.min(props.max, format(value) as number), props.min)
		}
		const onInput = (event:Event) => {
			const target = event.target as HTMLInputElement
			let value = target.value
			const _value = value
			value = value.replace(/\。/, '.')
			const formatted = formatString(value)
			const intFormatted = fxInstance.$fxUtils.floor(value) + ''
			if (fxInstance.$fxUtils.regInputNumber().test(value)) {
				currentValue.value = props.value as (string)
				return false
			}
			if (props.positive && Number(value) < 0) {
				currentValue.value = props.value as (string)
				return false
			} else if (fxInstance.$fxUtils.isDef(props.pointSize)) {
				if (
					(formatted.indexOf('.') === -1 && formatted.replace(/-/g, '').length > intLength) ||
					(formatted.indexOf('.') !== -1 && intFormatted.replace(/-/g, '').length > intLength) ||
					(formatted.indexOf('.') !== -1 && !computedNumberReg.value.test(formatted))
				) {
					currentValue.value = props.value as (string)
					return false
				}
			}
			if (_value !== formatted) {
				currentValue.value = formatted
			}
			if (formatted === '-') {
				return
			}
			emit('update:value', Number(formatted))
			emit('change', Number(formatted))
		}
		const onBlur = (event:Event) => {
			if (props.readonly || props.disabled) {
				event.preventDefault()
				return false
			}
			currentValue.value = range(currentValue.value)
			if (currentValue.value !== props.value) {
				emit('update:value', currentValue.value)
				emit('change', currentValue.value)
			}
			emit('blur', event)
		}
		const onFocus = (event:Event) => {
			if (props.readonly || props.disabled) {
				event.preventDefault()
				return false
			}
			if (props.value === 0) {
				currentValue.value = ''
			}
			if (props.autoSelect) {
				inputRef.value?.select()
			}
			emit('focus', event)
		}
		const focus = () => {
			inputRef.value?.focus()
		}
		const blur = () => {
			inputRef.value?.blur()
		}
		const placeholderComputed = computed(() => {
			if (props.value === 0) {
				return '0'
			}
			if (props.disabled) {
				return ''
			}
			return props.placeholder
		})
		watch(() => props.value, (val) => {
			if (val === '' || !fxInstance.$fxUtils.isDef(val)) {
				currentValue.value = ''
			} else if (val !== currentValue.value) {
				currentValue.value = format(val)
			}
		}, {
			immediate: true
		})
		const onKeydown = (event: KeyboardEvent) => {
			if (event.keyCode === 13) {
				emit('pressEnter')
			} else {
				emit('keydown', event)
			}
		}
		expose({
			focus,
			blur
		})
		return {
			inputRef,
			currentValue,
			onInput,
			onBlur,
			onFocus,
			onKeydown,
			placeholderComputed
		}
	}
})
</script>
<style lang="scss" scoped>
@import "$assets/stylus/varsty";
.wind-input-number {
    border: 0;
	&.has-border{
		margin: auto 0;
		margin-right: 5px;
		padding: 0 15px;
		width: 180px;
		height: 30px;
		border: 1px solid $fxGray1;
		border-radius: 15px;
		line-height: 30px;
	}
}
</style>
